class hmm_cnv_settings_t{
};

#ifdef USE_GPU
struct opencl_hmm_cnv_t{
  cl::CommandQueue command_queue;
  cl::Kernel kernel_forward_backward;
  //cl::Kernel kernel_viterbi;
  cl::Kernel kernel_forward;
  cl::Kernel kernel_backward;
  cl::Kernel kernel_likelihood;
  cl::Kernel kernel_posterior;
  cl::Kernel kernel_baumwelch_normalize;
  cl::Kernel kernel_baumwelch_transition;
  cl::Kernel kernel_baumwelch_emission;
  cl::Kernel kernel_rescale_transition;
  cl::Kernel kernel_zero_transition;
  cl::Kernel kernel_normalize_transition;
  cl::Buffer cn_vec_buffer;
  cl::Buffer transition_mat_buffer;
  cl::Buffer penalty_mat_buffer;
  cl::Buffer transition_new_mat_buffer;
  cl::Buffer scaled_forward_transition_mat_buffer;
  cl::Buffer forward_gap_buffer;
  cl::Buffer scaled_backward_transition_mat_buffer;
  cl::Buffer backward_gap_buffer;
  //cl::Buffer emission_mat_buffer;
  cl::Buffer emission_cache_mat_buffer;
  cl::Buffer observation_vec_buffer;
  cl::Buffer forward_mat_buffer;
  cl::Buffer backward_mat_buffer;
  cl::Buffer prob_mat_buffer;
  //cl::Buffer greedy_mat_buffer;
  //cl::Buffer bestpath_mat_buffer;
  //cl::Buffer backtrace_vec_buffer;
  cl::Buffer obs_index_buffer;
  cl::Buffer counter_index_buffer;
  cl::Buffer likelihood_log_buffer;
  cl::Buffer baumwelch_norm_buffer;
  
};
#endif

struct state_t;

class HMM_CNV:public Analyzer{
public:
  void init(const ptree & pt);
  HMM_CNV();
  ~HMM_CNV();
  void run();
  static const float small=1e-10;
private:
#ifdef USE_GPU
  opencl_hmm_cnv_t opencl_info;
  cl_int err;
#endif
  // These are input settings
  bool use_gpu;
  int platform_id;
  string platform_type;
  int device_id;
  string kernel_path;
  string observed_filelist;
  int total_markers;
  float * sd_lrr_het;
  float * sd_lrr_loh;
  float * sd_baf_percent;
  float sd_lrr_normal;
  float sd_baf_homo_del;
  float global_alpha;
  float normal_cdf;
  int normal_state;

  MathUtils * math;
  float * trans_mat; // transition matrix
  float * penalty_mat; // applies further penalties to transition matrix
  vector<string> filelist_vec; // list of filenames for input
  vector<float> global_alphas;
  string chr; // chr to operate on
  int * pos_vec; // positions in base pairs
  int * gap_vec; // inter-SNP distance in base pairs
  vector<state_t> state_object_vector; // vector of state objects
  string * rslist; // list of SNP IDs
  int samples; // total samples
  int observations; // total markers
  int states; // total states
  int iteration;  // current iteration
  float sd_baf_inflation; // inflation of standard deviation for BAF
  float sd_lrr_inflation; // inflation of standard deviation for R ratio
  float sd_alpha;
  int current_sample;
  int hmm_matrix_size;
  int trans_matrix_size;
 
  static const float intercept = .32;

  // these are large matrices MARKERS  * SUBJECTS
  float *lrr_vec;
  float *baf_vec;
  float *forward_mat_log,*backward_mat_log, *prob_mat_log;
  float * sample_trans_mat; // transition matrix
  //double *forward_mat_log,*backward_mat_log, *prob_mat_log;
  float * emission_cache_mat;

  // needed by GPU
  int * state_tumorcn_vec; // for use on GPU. copy numbers
  float * state_mu_lrr;
  float * sample_mu_lrr_adjusted;
  float * sample_likelihood_log;
  float * state_sd_lrr;
  float * state_het_ratio;
  float * state_total_alpha;
  //float * state_baf_het_mean;
  bool * state_alpha_ident;
  bool * state_het_ident;
  float * state_alpha_prior;
  vector<string> sample_annotations;
  
  // functions below
  float get_baf_mean(int bac,int cn, float alpha);
  float get_baf_sd(int state,int bac);
  bool load_observed_files(const string & filelist);
  float getBinomSum(int n, float pop_b, float baf);
  void init_emission_cache_mat_orig();
  void compute_emission_cache_mat(bool initgpu);
  void forwardbackward_cpu();
  //void viterbi_output();
  //void viterbi_cpu();
  //void viterbi_gpu();
  float emission_prob(int state,float lrr, float baf,float pfb,ostream & os);
  void marginalize_posteriors();
  void baumwelch_cpu();
  void init_state_objects(int current_sample);
  void forwardbackward_gpu();
  void baumwelch_gpu();
  double addMultipleLogs(double * logs, int len);
  void scaleTransitionMat(float * scaled_mat,int gap);
  void get_sd_mle(bool weighted);
  void get_alpha_mle();
  float get_lrr_offset();
  void init_gpu();
  //void set_global_alpha();
  //ofstream ofs;
};

struct state_t{
  state_t(int id,int tumor_cn,  float global_alpha, float alpha,  float het_ratio,bool alpha_identifiable, bool het_identifiable, float * sd_lrr_het, float * sd_lrr_loh, float  sd_lrr_normal);
  state_t();
  int id;
  float total_alpha;
  float het_ratio;
  //float baf_mean_precompute;
  bool alpha_ident;
  bool het_ident;
  //int alpha_block;
  int normal_bac; // B allele count
  int normal_cn;
  int tumor_bac;
  int tumor_cn;
  float mu_lrr;
  float sd_lrr;
  float alpha_prior;
  void debug();
     
};
